﻿using System;
using System.Net;
using System.Net.Cache;
using System.Net.Security;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Security.Principal;

namespace Downloader;

public class RequestConfiguration
{
    public RequestConfiguration()
    {
        Headers = new WebHeaderCollection();
        AllowAutoRedirect = true;
        AuthenticationLevel = AuthenticationLevel.MutualAuthRequested;
        AutomaticDecompression = DecompressionMethods.None;
        ClientCertificates = new X509CertificateCollection();
        ImpersonationLevel = TokenImpersonationLevel.Delegation;
        KeepAlive = false; // Please keep this in false. Because of an error (An existing connection was forcibly closed by the remote host)
        MaximumAutomaticRedirections = 50;
        Pipelined = true;
        ProtocolVersion = HttpVersion.Version11;
        Timeout = 30 * 1000; // 30 second
        UserAgent = $"{nameof(Downloader)}/{Assembly.GetExecutingAssembly().GetName().Version.ToString(3)}";
    }

    /// <summary>
    ///     A <see cref="string" /> containing the value of the HTTP Accept header. The default value of this property is null.
    ///     Note: For additional information see section 14.1 of IETF RFC 2616 - HTTP/1.1.
    /// </summary>
    public string Accept { get; set; }

    /// <summary>
    ///     Set <see cref="System.Net.HttpWebRequest.AllowAutoRedirect" /> to true to allow the current request to
    ///     automatically
    ///     follow HTTP redirection headers to the new location of a resource. Default value is true.
    ///     The maximum number of redirections to follow is set by the
    ///     <see cref="System.Net.HttpWebRequest.MaximumAutomaticRedirections" /> property.
    /// </summary>
    public bool AllowAutoRedirect { get; set; }

    /// <summary>
    ///     Gets or sets values indicating the level of authentication and impersonation used for this request.
    /// </summary>
    public AuthenticationLevel AuthenticationLevel { get; set; }

    /// <summary>
    ///     A <see cref="DecompressionMethods" /> object that indicates the type of decompression that is used.
    ///     Default value is None;
    /// </summary>
    /// <exception cref="InvalidOperationException">The object's current state does not allow this property to be set.</exception>
    public DecompressionMethods AutomaticDecompression { get; set; }

    /// <summary>
    ///     Gets or sets the cache policy for this request.
    /// </summary>
    public RequestCachePolicy CachePolicy { get; set; }

    /// <summary>
    ///     When overridden in a descendant class, gets or sets the name of the connection group for the request.
    /// </summary>
    public string ConnectionGroupName { get; set; }

    /// <summary>
    ///     The <see cref="X509CertificateCollection" /> that contains the security certificates associated with this request.
    /// </summary>
    /// <remarks>
    ///     The Framework caches SSL sessions as they are created and attempts to reuse a cached session for a new request, if
    ///     possible.
    ///     When attempting to reuse an SSL session, the Framework uses the first element of <see cref="ClientCertificates" />
    ///     (if there is one),
    ///     or tries to reuse an anonymous sessions if <see cref="ClientCertificates" /> is empty.
    ///     For performance reasons, you shouldn't add a client certificate to a
    ///     <see cref="HttpWebRequest" /> unless you know the server will ask for it.
    /// </remarks>
    /// <exception cref="ArgumentNullException">The value specified for a set operation is null.</exception>
    public X509CertificateCollection ClientCertificates { get; set; }

    /// <summary>
    ///     The ContentType property contains the media type of the request.
    ///     Values assigned to the ContentType property replace any existing contents
    ///     when the request sends the Content-type HTTP header.
    ///     The default value is null.
    /// </summary>
    public string ContentType { get; set; }

    /// <summary>
    ///     Gets or sets the cookies associated with the request.
    /// </summary>
    public CookieContainer CookieContainer { get; set; }

    /// <summary>
    ///     A <see cref="ICredentials" /> object containing the authentication
    ///     credentials associated with the current instance. The default is null.
    /// </summary>
    /// <remarks>
    ///     The <seealso cref="System.Net.HttpWebRequest.Credentials" /> property contains authentication
    ///     information to identify the client making the request. The <see cref="System.Net.HttpWebRequest.Credentials" />
    ///     property
    ///     can be either an instance of NetworkCredential, in which case the user, password,
    ///     and domain information contained in the NetworkCredential instance is used to authenticate the request,
    ///     or it can be an instance of CredentialCache, in which case the uniform resource identifier (URI)
    ///     of the request is used to determine the user, password, and domain information to use to authenticate the request.
    /// </remarks>
    public ICredentials Credentials { get; set; }

    /// <summary>
    ///     A <see cref="string" /> that contains the contents of the HTTP Expect header. The default value is null.
    ///     <exception cref="ArgumentException">
    ///         The value specified for a set operation is "100-continue". This value is case insensitive.
    ///     </exception>
    /// </summary>
    public string Expect { get; set; }

    /// <summary>
    ///     When overridden in a descendant class, gets or sets the collection of
    ///     header name/value pairs associated with the request.
    /// </summary>
    public WebHeaderCollection Headers { get; set; }

    /// <summary>
    ///     A <see cref="System.DateTime" /> that contains the contents of the HTTP If-Modified-Since header.
    ///     The default value is the current date and time of the system.
    ///     <remarks>
    ///         Note: For additional information see section 14.25 of IETF RFC 2616 - HTTP/1.1.
    ///     </remarks>
    /// </summary>
    public DateTime? IfModifiedSince { get; set; }

    /// <summary>
    ///     Gets or sets the impersonation level for the current request.
    /// </summary>
    public TokenImpersonationLevel ImpersonationLevel { get; set; }

    /// <summary>
    ///     An application uses <see cref="System.Net.HttpWebRequest.KeepAlive" /> to
    ///     indicate a preference for persistent connections. When this property is true,
    ///     the application makes persistent connections to the servers that support them.
    /// </summary>
    public bool KeepAlive { get; set; }

    /// <summary>
    ///     A <see cref="Int32" /> value that indicates the maximum number of redirection responses that the current instance
    ///     will follow.
    ///     The default value is implementation-specific.
    ///     <exception cref="ArgumentException">
    ///         The value specified for a set operation is less than or equal to zero.
    ///     </exception>
    /// </summary>
    public int MaximumAutomaticRedirections { get; set; }

    /// <summary>
    ///     A <see cref="string" /> that identifies the media type of the current request.
    ///     The default value is null.
    /// </summary>
    /// <remarks>
    ///     The value of this property affects the <seealso cref="System.Net.HttpWebResponse.CharacterSet" /> property.
    ///     When this property is set in the current instance,
    ///     the corresponding media type is chosen from the list of
    ///     character sets returned in the response HTTP Content-type header.
    /// </remarks>
    public string MediaType { get; set; }
    /// <summary>
    ///     An application uses this property to indicate a preference for pipelined connections.
    ///     If <see cref="System.Net.HttpWebRequest.Pipelined" /> is true ,
    ///     an application makes pipelined connections to servers that support them. The default is true.
    ///     Pipelined connections are made only when the <seealso cref="System.Net.HttpWebRequest.KeepAlive" /> property is
    ///     true.
    /// </summary>
    public bool Pipelined { get; set; }

    /// <summary>
    ///     Gets or sets a Boolean value that indicates whether to send HTTP preauthentication header
    ///     information with current instance without waiting for an authentication challenge
    ///     from the requested resource.
    ///     true to send a HTTP WWW-authenticate header with the current instance
    ///     without waiting for an authentication challenge from the requested resource;
    ///     otherwise, false . The default is false .
    /// </summary>
    public bool PreAuthenticate { get; set; }

    /// <summary>
    ///     A <see cref="System.Version" /> that represents the HTTP version to use for the request.
    ///     The default is <see cref="System.Net.HttpVersion.Version10" />.
    ///     The <seealso cref="System.Net.HttpWebRequest" /> class supports only versions 1.0 and 1.1 of HTTP.
    ///     Setting <see cref="System.Net.HttpWebRequest.ProtocolVersion" /> to a different version
    ///     causes a ArgumentException exception to be thrown.
    /// </summary>
    /// <exception cref="ArgumentException">
    ///     The HTTP version is set to a value other than 1.0 or 1.1.
    /// </exception>
    public Version ProtocolVersion { get; set; }

    /// <summary>
    ///     The <see cref="System.Net.HttpWebRequest.Proxy" /> property identifies
    ///     the WebProxy instance to use to communicate with the destination server.
    ///     To specify that no proxy should be used, set the <see cref="System.Net.HttpWebRequest" />.
    ///     Default value is null.
    /// </summary>
    /// <exception cref="ArgumentNullException">A set operation was requested and the specified value was null .</exception>
    /// <exception cref="InvalidOperationException">
    ///     A set operation was requested but data has already been sent to the request
    ///     stream.
    /// </exception>
    /// <exception cref="System.Security.SecurityException">The caller does not have permission for the requested operation.</exception>
    public IWebProxy Proxy { get; set; }

    /// <summary>
    ///     A <see cref="string" /> containing the value of the HTTP Referer header. The default value is null.
    ///     Note: For additional information see section 14.36 of IETF RFC 2616 - HTTP/1.1.
    /// </summary>
    public string Referer { get; set; }

    /// <summary>
    ///     When System.Net.HttpWebRequest.SendChunked is true , the request sends data to the destination in segments.
    ///     The destination server is required to support receiving chunked data. The default value is false.
    ///     Set this property to true only if the server specified by the System.Net.HttpWebRequest.
    ///     Address property of the current instance accepts chunked data (i.e. is HTTP/1.1 or greater in compliance).
    ///     If the server does not accept chunked data, buffer all data to be written and send a HTTP Content-Length header
    ///     with the buffered data.
    /// </summary>
    /// <exception cref="InvalidOperationException">
    ///     A set operation was requested but data has already been written to the
    ///     request data stream.
    /// </exception>
    public bool SendChunked { get; set; }

    public int Timeout { get; set; }

    /// <summary>
    ///     A String that contains the value of the HTTP Transfer-encoding header. The default value is null.
    ///     Clearing <see cref="System.Net.HttpWebRequest.TransferEncoding" /> by setting it to null has no effect
    ///     on the value of <see cref="System.Net.HttpWebRequest.SendChunked" />.
    ///     Values assigned to the <see cref="System.Net.HttpWebRequest.TransferEncoding" /> property replace any existing
    ///     contents.
    ///     For additional information see section 14.41 of IETF RFC 2616 - HTTP/1.1.
    /// </summary>
    /// <exception cref="InvalidOperationException">
    ///     <see cref="System.Net.HttpWebRequest.TransferEncoding" /> is set when
    ///     <see cref="System.Net.HttpWebRequest.SendChunked" /> is false.
    /// </exception>
    /// <exception cref="ArgumentException">
    ///     <see cref="System.Net.HttpWebRequest.TransferEncoding" /> is set to the value "Chunked". This value is case
    ///     insensitive.
    /// </exception>
    public string TransferEncoding { get; set; }

    /// <summary>
    ///     true if the default credentials are used; otherwise, false. The default value is false.
    ///     Set this property to true when requests made by this <see cref="HttpWebRequest" /> object should,
    ///     if requested by the server, be authenticated using the credentials of the currently logged on user.
    ///     For client applications, this is the desired behavior in most scenarios. For middle-tier applications,
    ///     such as ASP.NET applications, instead of using this property, you would typically
    ///     set the <c>Credentials</c> property to the credentials of the client on whose behalf the request is made.
    /// </summary>
    /// <exception cref="InvalidOperationException">You attempted to set this property after the request was sent.</exception>
    public bool UseDefaultCredentials { get; set; }

    /// <summary>
    ///     A <see cref="string" /> containing the value of the HTTP User-agent header.
    ///     The default value is "<seealso cref="Downloader" />/{<seealso cref="Version" />}".
    /// </summary>
    public string UserAgent { get; set; }
}